-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce a test drive mode into the onboarding process #9109
Changes from 26 commits
2b0d340
57547a7
08fe035
b67bd92
387440e
f1e138d
2cb4c68
8269574
5e8b5f9
d98fc5c
2c3fee0
c489d99
c503f62
1953e1d
5faf107
b98d260
d658133
9f734ec
d361ffb
69cc111
3504b3e
215c82b
63a625e
cc9478b
0d9044a
a924d18
9a2e2c6
f80fea1
3a84f96
bf80405
deaf1af
a21c718
0d48264
35078f1
7f4dc19
cb2c16b
058c592
0bd7eb8
7a989fb
a56bad4
f94fcb3
ded3690
d8d0e05
10ab2ee
164ea6c
a97f96b
0309f3c
9618aa2
c34320d
1d61c0c
45eff84
064d10e
a3dd2a6
85cdfd6
5bb8f08
49d4f60
1ea0e0a
3392118
668fa62
7d47f18
9bd946d
8434523
9a893d5
19da916
97b13ca
515bef4
2c09ae8
4cbd41a
b9b77ee
9afe041
b2af679
81121b5
7d37c45
fbe7b82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: minor | ||
Type: add | ||
|
||
Introduce test-drive mode into the onboarding process, replacing the existing Sandbox mode. | ||
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,7 +3,7 @@ | |||||
/** | ||||||
* External dependencies | ||||||
*/ | ||||||
import React, { useEffect, useState } from 'react'; | ||||||
import React, { useEffect, useState, useRef } from 'react'; | ||||||
import { render } from '@wordpress/element'; | ||||||
import { | ||||||
Button, | ||||||
|
@@ -15,6 +15,7 @@ import { | |||||
} from '@wordpress/components'; | ||||||
import apiFetch from '@wordpress/api-fetch'; | ||||||
import { addQueryArgs } from '@wordpress/url'; | ||||||
import { Loader } from '@woocommerce/onboarding'; | ||||||
|
||||||
/** | ||||||
* Internal dependencies | ||||||
|
@@ -30,13 +31,41 @@ import strings from './strings'; | |||||
import './style.scss'; | ||||||
import InlineNotice from 'components/inline-notice'; | ||||||
import { WooPaymentMethodsLogos } from 'components/payment-method-logos'; | ||||||
import WooPaymentsLogo from 'assets/images/logo.svg?asset'; | ||||||
import { __ } from '@wordpress/i18n'; | ||||||
|
||||||
interface AccountData { | ||||||
status: string; | ||||||
} | ||||||
|
||||||
const SandboxModeNotice = () => ( | ||||||
<BannerNotice icon status="warning" isDismissible={ false }> | ||||||
{ strings.sandboxModeNotice } | ||||||
</BannerNotice> | ||||||
); | ||||||
|
||||||
const TestDriveLoader: React.FunctionComponent< { | ||||||
progress: number; | ||||||
} > = ( { progress } ) => ( | ||||||
<Loader className="connect-account-page__preloader"> | ||||||
<img src={ WooPaymentsLogo } alt="" /> | ||||||
<Loader.Layout> | ||||||
<Loader.Title> | ||||||
{ __( | ||||||
'Creating your sandbox account', | ||||||
mordeth marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
'woocommerce-payments' | ||||||
) } | ||||||
</Loader.Title> | ||||||
<Loader.ProgressBar progress={ progress ?? 0 } /> | ||||||
<Loader.Sequence interval={ 0 }> | ||||||
{ __( | ||||||
'In just a few moments, you will be ready to test payments on your store.' | ||||||
) } | ||||||
</Loader.Sequence> | ||||||
</Loader.Layout> | ||||||
</Loader> | ||||||
); | ||||||
|
||||||
const ConnectAccountPage: React.FC = () => { | ||||||
const firstName = wcSettings.admin?.currentUserData?.first_name; | ||||||
const incentive = wcpaySettings.connectIncentive; | ||||||
|
@@ -47,9 +76,23 @@ const ConnectAccountPage: React.FC = () => { | |||||
wcpaySettings.errorMessage | ||||||
); | ||||||
const [ isSubmitted, setSubmitted ] = useState( false ); | ||||||
const [ isSandboxModeClicked, setSandboxModeClicked ] = useState( false ); | ||||||
const [ isTestDriveModeSubmitted, setTestDriveModeSubmitted ] = useState( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest we keep this variable the same |
||||||
false | ||||||
); | ||||||
const [ isTestDriveModeModalShown, setTestDriveModeModalShown ] = useState( | ||||||
false | ||||||
); | ||||||
const [ testDriveLoaderProgress, setTestDriveLoaderProgress ] = useState( | ||||||
5 | ||||||
); | ||||||
|
||||||
//creating a reference object | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const loaderProgressRef = useRef( testDriveLoaderProgress ); | ||||||
loaderProgressRef.current = testDriveLoaderProgress; | ||||||
|
||||||
const { | ||||||
connectUrl, | ||||||
overviewUrl, | ||||||
connect: { availableCountries, country }, | ||||||
devMode, | ||||||
} = wcpaySettings; | ||||||
|
@@ -74,6 +117,131 @@ const ConnectAccountPage: React.FC = () => { | |||||
return source; | ||||||
}; | ||||||
|
||||||
const updateLoaderProgress = ( maxPercent: number, step: number ) => { | ||||||
if ( loaderProgressRef.current < maxPercent ) { | ||||||
const newProgress = loaderProgressRef.current + step; | ||||||
setTestDriveLoaderProgress( newProgress ); | ||||||
} | ||||||
}; | ||||||
|
||||||
const checkAccountStatus = () => { | ||||||
// Fetch account status from the cache. | ||||||
apiFetch( { | ||||||
path: `/wc/v3/payments/accounts`, | ||||||
method: 'GET', | ||||||
} ).then( ( account ) => { | ||||||
// Simulate the update of the loader progress bar by 4% per check. | ||||||
// Limit to a maximum of 15 checks or 30 seconds. | ||||||
updateLoaderProgress( 100, 4 ); | ||||||
|
||||||
// If the account status is complete or progress percentage is above 95, redirect to the overview page. | ||||||
// Otherwise, schedule another check after 2 seconds. | ||||||
if ( | ||||||
( account as AccountData ).status === 'complete' || | ||||||
loaderProgressRef.current > 95 | ||||||
) { | ||||||
setTestDriveLoaderProgress( 100 ); | ||||||
const redirectUrl = addQueryArgs( overviewUrl, { | ||||||
'sandbox-onboarded': true, | ||||||
} ); | ||||||
window.location.href = redirectUrl; | ||||||
} else { | ||||||
setTimeout( checkAccountStatus, 2000 ); | ||||||
} | ||||||
} ); | ||||||
}; | ||||||
|
||||||
const trackConnectAccountClicked = ( sandboxMode: boolean ) => { | ||||||
recordEvent( 'wcpay_connect_account_clicked', { | ||||||
anu-rock marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
wpcom_connection: wcpaySettings.isJetpackConnected ? 'Yes' : 'No', | ||||||
is_new_onboarding_flow: isNewFlowEnabled, | ||||||
...( incentive && { | ||||||
incentive_id: incentive.id, | ||||||
} ), | ||||||
sandbox_mode: sandboxMode, | ||||||
path: 'payments_connect_v2', | ||||||
source: determineTrackingSource(), | ||||||
} ); | ||||||
}; | ||||||
|
||||||
const handleSetupTestDriveMode = async () => { | ||||||
setTestDriveLoaderProgress( 5 ); | ||||||
anu-rock marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
setTestDriveModeSubmitted( true ); | ||||||
trackConnectAccountClicked( true ); | ||||||
|
||||||
// Scroll the page to the top to ensure the logo is visible. | ||||||
window.scrollTo( { | ||||||
top: 0, | ||||||
} ); | ||||||
|
||||||
const url = addQueryArgs( connectUrl, { | ||||||
test_mode: true, | ||||||
test_drive: true, | ||||||
} ); | ||||||
|
||||||
const updateProgress = setInterval( updateLoaderProgress, 2500, 40, 5 ); | ||||||
|
||||||
// If Jetpack is connected, we should proceed with AJAX onboarding. | ||||||
// Otherwise, redirect to the Jetpack connect screen. | ||||||
if ( wcpaySettings.isJetpackConnected ) { | ||||||
setTestDriveModeModalShown( true ); | ||||||
fetch( url, { | ||||||
method: 'GET', | ||||||
redirect: 'follow', | ||||||
credentials: 'same-origin', | ||||||
headers: { | ||||||
'Content-Type': 'application/json', | ||||||
}, | ||||||
} ).then( ( response ) => { | ||||||
clearInterval( updateProgress ); | ||||||
setTestDriveLoaderProgress( 40 ); | ||||||
|
||||||
// Check the response url for the `wcpay-connection-success` parameter, | ||||||
// indicating a successful connection. | ||||||
const urlParams = new URLSearchParams( response.url ); | ||||||
const connected = | ||||||
urlParams.get( 'wcpay-connection-success' ) || ''; | ||||||
|
||||||
// The account has been successfully onboarded. | ||||||
// Start checking the account status every 2 seconds. | ||||||
// Once the status is complete, redirect to the Overview page. | ||||||
if ( connected === '1' ) { | ||||||
checkAccountStatus(); | ||||||
} else { | ||||||
// Set the error message. | ||||||
setErrorMessage( | ||||||
__( | ||||||
'An error occurred while creating a sandbox account. Please try again!', | ||||||
'woocommerce-payments' | ||||||
) | ||||||
); | ||||||
|
||||||
// Scroll window to the top | ||||||
window.scrollTo( { | ||||||
top: 0, | ||||||
} ); | ||||||
|
||||||
// Hide loader. | ||||||
setTestDriveModeModalShown( false ); | ||||||
setTestDriveModeSubmitted( false ); | ||||||
} | ||||||
} ); | ||||||
} else { | ||||||
window.location.href = url; | ||||||
} | ||||||
}; | ||||||
|
||||||
const forceOnboardTestDrive = () => { | ||||||
const urlParams = new URLSearchParams( window.location.search ); | ||||||
const forceOnboard = urlParams.get( 'force-test-onboard' ) || false; | ||||||
|
||||||
// If the force test onboard is present and Jetpack is connected | ||||||
// we should start onboarding Test Drive account automatically. | ||||||
if ( forceOnboard && wcpaySettings.isJetpackConnected ) { | ||||||
handleSetupTestDriveMode(); | ||||||
} | ||||||
}; | ||||||
|
||||||
useEffect( () => { | ||||||
recordEvent( 'page_view', { | ||||||
path: 'payments_connect_v2', | ||||||
|
@@ -82,6 +250,8 @@ const ConnectAccountPage: React.FC = () => { | |||||
} ), | ||||||
source: determineTrackingSource(), | ||||||
} ); | ||||||
|
||||||
forceOnboardTestDrive(); | ||||||
// We only want to run this once. | ||||||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||||||
}, [] ); | ||||||
|
@@ -116,19 +286,6 @@ const ConnectAccountPage: React.FC = () => { | |||||
document.body.appendChild( container ); | ||||||
}; | ||||||
|
||||||
const trackConnectAccountClicked = ( sandboxMode: boolean ) => { | ||||||
recordEvent( 'wcpay_connect_account_clicked', { | ||||||
wpcom_connection: wcpaySettings.isJetpackConnected ? 'Yes' : 'No', | ||||||
is_new_onboarding_flow: isNewFlowEnabled, | ||||||
...( incentive && { | ||||||
incentive_id: incentive.id, | ||||||
} ), | ||||||
sandbox_mode: sandboxMode, | ||||||
path: 'payments_connect_v2', | ||||||
source: determineTrackingSource(), | ||||||
} ); | ||||||
}; | ||||||
|
||||||
const handleSetup = async () => { | ||||||
setSubmitted( true ); | ||||||
|
||||||
|
@@ -158,18 +315,6 @@ const ConnectAccountPage: React.FC = () => { | |||||
window.location.href = connectUrl; | ||||||
}; | ||||||
|
||||||
const handleEnableSandboxMode = async () => { | ||||||
setSandboxModeClicked( true ); | ||||||
|
||||||
trackConnectAccountClicked( true ); | ||||||
|
||||||
const url = addQueryArgs( connectUrl, { | ||||||
test_mode: true, | ||||||
create_builder_account: true, | ||||||
} ); | ||||||
window.location.href = url; | ||||||
}; | ||||||
|
||||||
return ( | ||||||
<Page isNarrow className="connect-account-page"> | ||||||
{ errorMessage && ( | ||||||
|
@@ -272,16 +417,19 @@ const ConnectAccountPage: React.FC = () => { | |||||
</InlineNotice> | ||||||
<Button | ||||||
variant="secondary" | ||||||
isBusy={ isSandboxModeClicked } | ||||||
disabled={ isSandboxModeClicked } | ||||||
onClick={ handleEnableSandboxMode } | ||||||
isBusy={ isTestDriveModeSubmitted } | ||||||
disabled={ isTestDriveModeSubmitted } | ||||||
onClick={ handleSetupTestDriveMode } | ||||||
> | ||||||
{ strings.button.sandbox } | ||||||
</Button> | ||||||
</PanelBody> | ||||||
</Panel> | ||||||
</> | ||||||
) } | ||||||
{ isTestDriveModeModalShown && ( | ||||||
<TestDriveLoader progress={ testDriveLoaderProgress } /> | ||||||
) } | ||||||
</Page> | ||||||
); | ||||||
}; | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, this is true. But the change will come across differently to the user as we have not rebranded sandbox mode as test-drive mode in the UI (a good question to @timmy5685 @orcunomattic @vladolaru whether we should do it).
For now, a clearer message could be:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, since this is an important UX change, I think we should explain it properly in the 8.1 What's New post.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On another thought, maybe the rebranding is not required as we'll kind of cover that as part of Native Onboarding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the Native Onboarding work comes into play, updating the "sandbox" language to "test mode" makes sense as we’ll be referring to it as a test mode in other places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given it wasn't so long ago that we introduced the concept of sandbox mode, which was a rebranding of dev mode, I think we should continue to refer to this as sandbox mode at least in the short term, until we get to the Native onboarding work.
So IMO for now, @anu-rock's suggestion is perfect and we should be careful that we continue to use the language sandbox mode externally when referring to the "test-drive" feature.