diff --git a/changelog/dev-3468-allow-reset-account-management b/changelog/dev-3468-allow-reset-account-management new file mode 100644 index 00000000000..ed030674f95 --- /dev/null +++ b/changelog/dev-3468-allow-reset-account-management @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add Account Management tools with reset account functionality for partially onboarded accounts. diff --git a/client/components/account-status/account-fees/index.js b/client/components/account-status/account-fees/index.js index 066a4faf1b3..93a93293c11 100644 --- a/client/components/account-status/account-fees/index.js +++ b/client/components/account-status/account-fees/index.js @@ -16,6 +16,8 @@ import { getCurrentBaseFee, getTransactionsPaymentMethodName, } from 'utils/account-fees'; +import { CardDivider } from '@wordpress/components'; +import './styles.scss'; const AccountFee = ( props ) => { const { accountFee, paymentMethod } = props; @@ -59,7 +61,12 @@ const AccountFees = ( props ) => { return ( <> { haveDiscounts && ( -

{ __( 'Active discounts', 'woocommerce-payments' ) }

+
+ +

+ { __( 'Active discounts', 'woocommerce-payments' ) } +

+
) } { activeDiscounts } diff --git a/client/components/account-status/account-fees/styles.scss b/client/components/account-status/account-fees/styles.scss new file mode 100644 index 00000000000..9938ef462b1 --- /dev/null +++ b/client/components/account-status/account-fees/styles.scss @@ -0,0 +1,3 @@ +.account-fees { + padding-top: 16px; +} diff --git a/client/components/account-status/account-fees/test/__snapshots__/index.js.snap b/client/components/account-status/account-fees/test/__snapshots__/index.js.snap index 6a2576c6862..653e680afac 100644 --- a/client/components/account-status/account-fees/test/__snapshots__/index.js.snap +++ b/client/components/account-status/account-fees/test/__snapshots__/index.js.snap @@ -2,9 +2,20 @@ exports[`AccountFees renders discounted base fee 1`] = `
-

- Active discounts -

+
+ +

+ Active discounts +

+

Card transactions : @@ -47,9 +58,20 @@ exports[`AccountFees renders discounted base fee 1`] = ` exports[`AccountFees renders discounted fee with USD volume currency and non-USD base fee 1`] = `

-

- Active discounts -

+

Card transactions : @@ -92,9 +114,20 @@ exports[`AccountFees renders discounted fee with USD volume currency and non-USD exports[`AccountFees renders discounted fee with end date 1`] = `

-

- Active discounts -

+

Card transactions : @@ -115,9 +148,20 @@ exports[`AccountFees renders discounted fee with end date 1`] = ` exports[`AccountFees renders discounted fee with volume limit 1`] = `

-

- Active discounts -

+

Card transactions : @@ -160,9 +204,20 @@ exports[`AccountFees renders discounted fee with volume limit 1`] = ` exports[`AccountFees renders discounted fee with volume limit and end date 1`] = `

-

- Active discounts -

+

Card transactions : @@ -205,9 +260,20 @@ exports[`AccountFees renders discounted fee with volume limit and end date 1`] = exports[`AccountFees renders discounted fee without volume limit 1`] = `

-

- Active discounts -

+

Card transactions : @@ -223,9 +289,20 @@ exports[`AccountFees renders discounted fee without volume limit 1`] = ` exports[`AccountFees renders discounted non-USD base fee 1`] = `

-

- Active discounts -

+

Card transactions : @@ -268,9 +345,20 @@ exports[`AccountFees renders discounted non-USD base fee 1`] = ` exports[`AccountFees renders discounts multiple payment methods 1`] = `

-

- Active discounts -

+

Card transactions : @@ -306,9 +394,20 @@ exports[`AccountFees renders discounts multiple payment methods 1`] = ` exports[`AccountFees renders first discounted fee ignoring the rest 1`] = `

-

- Active discounts -

+

Card transactions : @@ -324,9 +423,20 @@ exports[`AccountFees renders first discounted fee ignoring the rest 1`] = ` exports[`AccountFees renders non-USD base fee 1`] = `

-

- Active discounts -

+

Card transactions : @@ -342,9 +452,20 @@ exports[`AccountFees renders non-USD base fee 1`] = ` exports[`AccountFees renders normal base fee 1`] = `

-

- Active discounts -

+

Card transactions : diff --git a/client/components/account-status/account-tools/index.tsx b/client/components/account-status/account-tools/index.tsx new file mode 100644 index 00000000000..1a7d8039829 --- /dev/null +++ b/client/components/account-status/account-tools/index.tsx @@ -0,0 +1,67 @@ +/** + * External dependencies + */ +import React, { useState } from 'react'; +import { Button, CardDivider } from '@wordpress/components'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Internal dependencies + */ +import strings from './strings'; +import { isInDevMode } from 'utils'; +import './styles.scss'; +import ResetAccountModal from 'wcpay/overview/modal/reset-account'; +import { trackAccountReset } from 'wcpay/onboarding/tracking'; + +interface Props { + accountLink: string; + openModal: () => void; +} + +const handleReset = () => { + trackAccountReset(); + + window.location.href = addQueryArgs( wcpaySettings.connectUrl, { + 'wcpay-reset-account': true, + } ); +}; + +export const AccountTools: React.FC< Props > = ( props: Props ) => { + const accountLink = props.accountLink; + const [ modalVisible, setModalVisible ] = useState( false ); + + if ( isInDevMode() ) return null; + + return ( + <> +

+ +

{ strings.title }

+

{ strings.description }

+ { /* Use wrapping div to keep buttons grouped together. */ } +
+ + +
+
+ + setModalVisible( false ) } + onSubmit={ handleReset } + /> + + ); +}; diff --git a/client/components/account-status/account-tools/strings.tsx b/client/components/account-status/account-tools/strings.tsx new file mode 100644 index 00000000000..47c668d0a88 --- /dev/null +++ b/client/components/account-status/account-tools/strings.tsx @@ -0,0 +1,15 @@ +/* eslint-disable max-len */ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; + +export default { + title: __( 'Account Tools', 'woocommerce-payments' ), + description: __( + '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.', + 'woocommerce-payments' + ), + finish: __( 'Finish setup', 'woocommerce-payments' ), + reset: __( 'Reset account', 'woocommerce-payments' ), +}; diff --git a/client/components/account-status/account-tools/styles.scss b/client/components/account-status/account-tools/styles.scss new file mode 100644 index 00000000000..aa2a29348cd --- /dev/null +++ b/client/components/account-status/account-tools/styles.scss @@ -0,0 +1,11 @@ +.account-tools { + padding-top: $gap; + + &__actions { + display: grid; + grid-auto-flow: column; + grid-auto-columns: max-content; + column-gap: $gap-small; + margin-top: $gap-small; + } +} diff --git a/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap b/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000000..cfeba86037a --- /dev/null +++ b/client/components/account-status/account-tools/test/__snapshots__/index.test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AccountTools should render in live mode 1`] = ` +
+ +
+`; diff --git a/client/components/account-status/account-tools/test/index.test.tsx b/client/components/account-status/account-tools/test/index.test.tsx new file mode 100644 index 00000000000..7c5827b115a --- /dev/null +++ b/client/components/account-status/account-tools/test/index.test.tsx @@ -0,0 +1,49 @@ +/** @format */ +/** + * External dependencies + */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import { AccountTools } from '..'; + +const accountLink = '/onboarding'; +const openModal = jest.fn(); + +declare const global: { + wcpaySettings: { + devMode: boolean; + }; +}; + +describe( 'AccountTools', () => { + it( 'should render in live mode', () => { + global.wcpaySettings = { + devMode: false, + }; + + const { container } = render( + + ); + expect( container ).toMatchSnapshot(); + } ); + + it( 'should not render in dev mode', () => { + global.wcpaySettings = { + devMode: true, + }; + + render( + + ); + + expect( + screen.queryByText( + '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.' + ) + ).not.toBeInTheDocument(); + } ); +} ); diff --git a/client/components/account-status/index.js b/client/components/account-status/index.js index 6a35084ad18..19fc715b1ff 100755 --- a/client/components/account-status/index.js +++ b/client/components/account-status/index.js @@ -23,6 +23,7 @@ import PaymentsStatus from 'components/payments-status'; import StatusChip from './status-chip'; import './style.scss'; import './shared.scss'; +import { AccountTools } from './account-tools'; const AccountStatusCard = ( props ) => { const { title, children, value } = props; @@ -102,6 +103,9 @@ const AccountStatusDetails = ( props ) => { } /> + { ! accountStatus.detailsSubmitted && ( + + ) } { accountFees.length > 0 && ( ) } diff --git a/client/components/account-status/test/__snapshots__/index.js.snap b/client/components/account-status/test/__snapshots__/index.js.snap index edead6f2fbd..712f139c0ca 100644 --- a/client/components/account-status/test/__snapshots__/index.js.snap +++ b/client/components/account-status/test/__snapshots__/index.js.snap @@ -166,9 +166,53 @@ exports[`AccountStatus renders normal status 1`] = `
-

- Active discounts -

+ +

Card transactions : diff --git a/client/onboarding/tracking.ts b/client/onboarding/tracking.ts index 3a083eeb64b..66ea41ebf60 100644 --- a/client/onboarding/tracking.ts +++ b/client/onboarding/tracking.ts @@ -57,6 +57,9 @@ export const trackRedirected = ( isEligible: boolean ): void => { } ); }; +export const trackAccountReset = (): void => + wcpayTracks.recordEvent( wcpayTracks.events.ONBOARDING_FLOW_RESET, {} ); + export const trackEligibilityModalClosed = ( action: 'dismiss' | 'setup_deposits' | 'enable_payments_only' ): void => diff --git a/client/overview/modal/reset-account/index.tsx b/client/overview/modal/reset-account/index.tsx new file mode 100644 index 00000000000..1146645566c --- /dev/null +++ b/client/overview/modal/reset-account/index.tsx @@ -0,0 +1,64 @@ +/** + * External dependencies + */ +import React from 'react'; +import { Button, CardDivider, Modal } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import './style.scss'; +import strings from './strings'; + +interface Props { + isVisible: boolean; + onSubmit: () => void; + onDismiss: () => void; +} + +const ResetAccountModal: React.FC< Props > = ( props: Props ) => { + const { isVisible, onDismiss, onSubmit } = props; + if ( ! isVisible ) return null; + + return ( + +

+

{ strings.description }

+

+ { strings.beforeContinue } +

+
    +
  1. { strings.step1 }
  2. +
+ +
    +
  1. { strings.step2 }
  2. +
+ +
    +
  1. { strings.step3 }
  2. +
+ +

{ strings.confirmation }

+
+
+ + +
+ + ); +}; + +export default ResetAccountModal; diff --git a/client/overview/modal/reset-account/strings.tsx b/client/overview/modal/reset-account/strings.tsx new file mode 100644 index 00000000000..1a1c7616ff0 --- /dev/null +++ b/client/overview/modal/reset-account/strings.tsx @@ -0,0 +1,36 @@ +/* eslint-disable max-len */ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +export default { + title: __( 'Reset account', 'woocommerce-payments' ), + description: __( + '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.', + 'woocommerce-payments' + ), + beforeContinue: __( 'Before you continue', 'woocommerce-payments' ), + step1: sprintf( + /* translators: %s: WooPayments. */ + __( + 'Your %s account will be reset, and all data will be lost.', + 'woocommerce-payments' + ), + 'WooPayments' + ), + step2: __( + 'You will have to re-confirm your business and banking details.', + 'woocommerce-payments' + ), + step3: __( + 'Once confirmed, this cannot be undone.', + 'woocommerce-payments' + ), + confirmation: __( + 'Are you sure you want to continue?', + 'woocommerce-payments' + ), + cancel: __( 'Cancel', 'woocommerce-payments' ), + reset: __( 'Yes, reset account', 'woocommerce-payments' ), +}; diff --git a/client/overview/modal/reset-account/style.scss b/client/overview/modal/reset-account/style.scss new file mode 100644 index 00000000000..1c0f9fc0f36 --- /dev/null +++ b/client/overview/modal/reset-account/style.scss @@ -0,0 +1,25 @@ +.wcpay-reset-account-modal { + // fix for the modal being too short on smaller screens + @media ( max-height: 880px ) { + max-height: 100% !important; + } + + .components-modal__content { + box-sizing: border-box; + max-width: 700px; + } + + &__footer { + text-align: right; + margin-top: $gap-large; + + & :first-child { + margin-right: $gap-smaller; + } + + button { + margin-top: $gap; + padding: $gap-smaller $gap; + } + } +} diff --git a/client/overview/modal/reset-account/test/index.test.tsx b/client/overview/modal/reset-account/test/index.test.tsx new file mode 100644 index 00000000000..50f55e78bbe --- /dev/null +++ b/client/overview/modal/reset-account/test/index.test.tsx @@ -0,0 +1,35 @@ +/** + * External dependencies + */ +import React from 'react'; +import { render, screen } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import ResetAccountModal from '..'; + +jest.mock( '@wordpress/data', () => ( { + useDispatch: jest.fn().mockReturnValue( { updateOptions: jest.fn() } ), +} ) ); + +const onSubmit = jest.fn(); +const onDismiss = jest.fn(); + +describe( 'Reset Account Modal', () => { + it( 'modal is open when is visible is true', () => { + render( + + ); + + expect( + screen.queryByText( + '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.' + ) + ).toBeInTheDocument(); + } ); +} ); diff --git a/client/tracks/index.js b/client/tracks/index.js index c02615f781d..c862f189954 100644 --- a/client/tracks/index.js +++ b/client/tracks/index.js @@ -124,6 +124,7 @@ const events = { ONBOARDING_FLOW_HIDDEN: 'wcpay_onboarding_flow_hidden', ONBOARDING_FLOW_EXITED: 'wcpay_onboarding_flow_exited', ONBOARDING_FLOW_REDIRECTED: 'wcpay_onboarding_flow_redirected', + ONBOARDING_FLOW_RESET: 'wcpay_onboarding_flow_reset', ONBOARDING_FLOW_ELIGIBILITY_MODAL_CLOSED: 'wcpay_onboarding_flow_eligibility_modal_closed', }; diff --git a/client/utils/index.js b/client/utils/index.js index 88756614649..d6e7a1c971d 100644 --- a/client/utils/index.js +++ b/client/utils/index.js @@ -22,6 +22,20 @@ export const isInTestMode = ( fallback = false ) => { return wcpaySettings.testMode === '1' || fallback; }; +/** + * Returns true if WooPayments is in dev mode, false otherwise. + * + * @param {boolean} fallback Fallback in case dev mode value can't be found (for example if the wcpaySettings are undefined). + * + * @return {boolean} True if in dev mode, false otherwise. Fallback value if test/dev mode value can't be found. + */ +export const isInDevMode = ( fallback = false ) => { + if ( typeof wcpaySettings === 'undefined' ) { + return fallback; + } + return wcpaySettings.devMode === '1' || fallback; +}; + export const getAdminUrl = ( args ) => addQueryArgs( 'admin.php', args ); /** diff --git a/includes/class-wc-payments-account.php b/includes/class-wc-payments-account.php index 18567fe25b6..fa4d3b45e45 100644 --- a/includes/class-wc-payments-account.php +++ b/includes/class-wc-payments-account.php @@ -1048,6 +1048,15 @@ public function maybe_handle_onboarding() { return; } + if ( isset( $_GET['wcpay-reset-account'] ) ) { + $test_mode = WC_Payments_Onboarding_Service::is_test_mode_enabled(); + + // Delete the account. + $this->payments_api_client->delete_account( $test_mode ); + $this->redirect_to_onboarding_flow_page(); + return; + } + // Hide menu notification badge upon starting setup. update_option( 'wcpay_menu_badge_hidden', 'yes' );