Skip to content
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

Limits steps in onboarding based on previously completed state #2568

Draft
wants to merge 7 commits into
base: feature/2458-streamline-onboarding
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 41 additions & 21 deletions js/src/hooks/useGoogleMCPhoneNumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* Internal dependencies
*/
import { STORE_KEY } from '.~/data/constants';
import useGoogleMCAccount from './useGoogleMCAccount';

const emptyData = {
country: '',
Expand Down Expand Up @@ -40,29 +41,48 @@
* @return {PhoneNumber} The payload of parsed phone number associated with the Google Merchant Center account and its loaded state.
*/
export default function useGoogleMCPhoneNumber() {
return useSelect( ( select ) => {
const { getGoogleMCPhoneNumber } = select( STORE_KEY );
const { data: contact, loaded } = getGoogleMCPhoneNumber();
let data = emptyData;
const { googleMCAccount } = useGoogleMCAccount();

if ( contact ) {
// Prevent to call parsePhoneNumber with null.
const parsed = parsePhoneNumber( contact.phone_number || '' );
if ( parsed ) {
data = {
...parsed,
isValid: parsed.isValid(),
isVerified:
contact.phone_verification_status === 'verified',
display: parsed.formatInternational(),
return useSelect(
( select ) => {
let data = emptyData;

// If there is no MC account then there is no phone number data to fetch.
if ( ! googleMCAccount?.id ) {
return {
loaded: false,
data,
};
delete data.metadata;
}
}

return {
loaded,
data,
};
}, [] );
const { getGoogleMCContactInformation, hasFinishedResolution } =
select( STORE_KEY );

Check warning on line 59 in js/src/hooks/useGoogleMCPhoneNumber.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useGoogleMCPhoneNumber.js#L59

Added line #L59 was not covered by tests

const contact = getGoogleMCContactInformation();
const loaded = hasFinishedResolution(

Check warning on line 62 in js/src/hooks/useGoogleMCPhoneNumber.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useGoogleMCPhoneNumber.js#L61-L62

Added lines #L61 - L62 were not covered by tests
'getGoogleMCContactInformation'
);

if ( contact && loaded ) {
// Prevent to call parsePhoneNumber with null.
const parsed = parsePhoneNumber( contact.phone_number || '' );
if ( parsed ) {
data = {

Check warning on line 70 in js/src/hooks/useGoogleMCPhoneNumber.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useGoogleMCPhoneNumber.js#L70

Added line #L70 was not covered by tests
...parsed,
isValid: parsed.isValid(),
isVerified:
contact.phone_verification_status === 'verified',
display: parsed.formatInternational(),
};
delete data.metadata;

Check warning on line 77 in js/src/hooks/useGoogleMCPhoneNumber.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useGoogleMCPhoneNumber.js#L77

Added line #L77 was not covered by tests
}
}

return {

Check warning on line 81 in js/src/hooks/useGoogleMCPhoneNumber.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useGoogleMCPhoneNumber.js#L81

Added line #L81 was not covered by tests
loaded,
data,
};
},
[ googleMCAccount?.id ]
);
}
110 changes: 68 additions & 42 deletions js/src/hooks/useStoreAddress.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/**
* External dependencies
*/
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import useAppSelectDispatch from './useAppSelectDispatch';
import { STORE_KEY } from '.~/data/constants';
import useCountryKeyNameMap from './useCountryKeyNameMap';
import useGoogleMCAccount from './useGoogleMCAccount';

/**
* @typedef {import('.~/hooks/types.js').StoreAddress} StoreAddress
Expand Down Expand Up @@ -36,53 +42,73 @@
* @return {StoreAddressResult} Store address result.
*/
export default function useStoreAddress( source = 'wc' ) {
const {
data: contact,
hasFinishedResolution: loaded,
invalidateResolution: refetch,
} = useAppSelectDispatch( 'getGoogleMCContactInformation' );

const { googleMCAccount } = useGoogleMCAccount();
const countryNameDict = useCountryKeyNameMap();

let data = emptyData;
return useSelect(
( select ) => {
let data = emptyData;

// If there is no MC account then there is no store address data to fetch.
if ( ! googleMCAccount?.id ) {
return {
refetch: () => {},

Check warning on line 55 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L55

Added line #L55 was not covered by tests
loaded: false,
data,
};
}

const {
getGoogleMCContactInformation,
hasFinishedResolution,
refetch,
} = select( STORE_KEY );

Check warning on line 65 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L65

Added line #L65 was not covered by tests

const contact = getGoogleMCContactInformation();
const loaded = hasFinishedResolution(

Check warning on line 68 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L67-L68

Added lines #L67 - L68 were not covered by tests
'getGoogleMCContactInformation'
);

if ( loaded && contact ) {
const {
is_mc_address_different: isMCAddressDifferent,
wc_address_errors: missingRequiredFields,
} = contact;
if ( contact && loaded ) {
const {
is_mc_address_different: isMCAddressDifferent,
wc_address_errors: missingRequiredFields,
} = contact;

Check warning on line 76 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L76

Added line #L76 was not covered by tests

const storeAddress =
source === 'wc' ? contact.wc_address : contact.mc_address;
const storeAddress =
source === 'wc' ? contact.wc_address : contact.mc_address;

// Handle fallback for `null` fields to make sure the returned data types are consistent.
const streetAddress = storeAddress?.street_address || '';
const city = storeAddress?.locality || '';
const state = storeAddress?.region || '';
const postcode = storeAddress?.postal_code || '';
// Handle fallback for `null` fields to make sure the returned data types are consistent.
const streetAddress = storeAddress?.street_address || '';
const city = storeAddress?.locality || '';
const state = storeAddress?.region || '';
const postcode = storeAddress?.postal_code || '';

const [ address, address2 = '' ] = streetAddress.split( '\n' );
const country = countryNameDict[ storeAddress?.country ] || '';
const countryCode = storeAddress?.country || '';
const isAddressFilled = ! missingRequiredFields.length;
const [ address, address2 = '' ] = streetAddress.split( '\n' );
const country = countryNameDict[ storeAddress?.country ] || '';
const countryCode = storeAddress?.country || '';
const isAddressFilled = ! missingRequiredFields.length;

Check warning on line 90 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L90

Added line #L90 was not covered by tests

data = {
countryCode,
address,
address2,
city,
state,
country,
postcode,
isAddressFilled,
isMCAddressDifferent,
missingRequiredFields,
};
}
data = {

Check warning on line 92 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L92

Added line #L92 was not covered by tests
countryCode,
address,
address2,
city,
state,
country,
postcode,
isAddressFilled,
isMCAddressDifferent,
missingRequiredFields,
};
}

return {
refetch,
loaded,
data,
};
return {

Check warning on line 106 in js/src/hooks/useStoreAddress.js

View check run for this annotation

Codecov / codecov/patch

js/src/hooks/useStoreAddress.js#L106

Added line #L106 was not covered by tests
refetch,
loaded,
data,
};
},
[ countryNameDict, googleMCAccount?.id, source ]
);
}
22 changes: 21 additions & 1 deletion js/src/setup-mc/setup-stepper/saved-setup-stepper.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import useTargetAudienceFinalCountryCodes from '.~/hooks/useTargetAudienceFinalCountryCodes';
import useSettings from '.~/components/free-listings/configure-product-listings/useSettings';
import useShippingRates from '.~/hooks/useShippingRates';
import useGoogleMCPhoneNumber from '.~/hooks/useGoogleMCPhoneNumber';
import useStoreAddress from '.~/hooks/useStoreAddress';
import useShippingTimes from '.~/hooks/useShippingTimes';
import useSaveShippingRates from '.~/hooks/useSaveShippingRates';
import useSaveShippingTimes from '.~/hooks/useSaveShippingTimes';
Expand All @@ -39,6 +41,20 @@
const SavedSetupStepper = ( { savedStep } ) => {
const [ step, setStep ] = useState( savedStep );

const { data: address, loaded: addressLoaded } = useStoreAddress();
const { data: phone, loaded: phoneLoaded } = useGoogleMCPhoneNumber();

const hasValidPhoneNumber =
phoneLoaded && phone?.isValid && phone?.isVerified;

const hasValidAddress =
addressLoaded &&
address?.isAddressFilled &&
! address?.isMCAddressDifferent;

Check warning on line 53 in js/src/setup-mc/setup-stepper/saved-setup-stepper.js

View check run for this annotation

Codecov / codecov/patch

js/src/setup-mc/setup-stepper/saved-setup-stepper.js#L52-L53

Added lines #L52 - L53 were not covered by tests

const hasConfirmedStoreRequirements =
hasValidPhoneNumber && hasValidAddress;

const { settings } = useSettings();
const { data: suggestedAudience } = useTargetAudienceWithSuggestions();
const { targetAudience, getFinalCountries } =
Expand Down Expand Up @@ -102,7 +118,11 @@
};

const handleSetupListingsContinue = () => {
continueStep( stepNameKeyMap.store_requirements );
if ( hasConfirmedStoreRequirements ) {
continueStep( stepNameKeyMap.paid_ads );

Check warning on line 122 in js/src/setup-mc/setup-stepper/saved-setup-stepper.js

View check run for this annotation

Codecov / codecov/patch

js/src/setup-mc/setup-stepper/saved-setup-stepper.js#L122

Added line #L122 was not covered by tests
} else {
continueStep( stepNameKeyMap.store_requirements );
}
};

const handleStoreRequirementsContinue = () => {
Expand Down
82 changes: 82 additions & 0 deletions tests/e2e/specs/setup-mc/step-3-hide-store-requirements.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Internal dependencies
*/
import SetUpAccountsPage from '../../utils/pages/setup-mc/step-1-set-up-accounts';

/**
* External dependencies
*/
const { test, expect } = require( '@playwright/test' );

test.use( { storageState: process.env.ADMINSTATE } );

test.describe.configure( { mode: 'serial' } );

/**
* @type {import('../../utils/pages/setup-mc/step-1-set-up-accounts.js').default} setUpAccountsPage
*/
let setUpAccountsPage = null;

/**
* @type {import('@playwright/test').Page} page
*/
let page = null;

test.describe( 'Hide Store Requirements Step', () => {
test.beforeAll( async ( { browser } ) => {
page = await browser.newPage();
setUpAccountsPage = new SetUpAccountsPage( page );
await Promise.all( [
// Mock google as connected.
setUpAccountsPage.mockGoogleNotConnected(),

// Mock MC contact information
setUpAccountsPage.mockContactInformation(),
] );
} );

test.afterAll( async () => {
await setUpAccountsPage.closePage();
} );

test( 'should have store requirements step if incomplete', async () => {
await setUpAccountsPage.goto();

// Mock MC step at step 1:
setUpAccountsPage.mockMCSetup( 'incomplete', 'accounts' );

// 1. Assert there are 3 steps
const steps = await page.locator( '.woocommerce-stepper__step' );
await expect( steps ).toHaveCount( 4 );

// 2. Assert the label of the 3rd step is 'Confirm store requirements'
const thirdStepLabel = await steps
.nth( 2 )
.locator( '.woocommerce-stepper__step-label' );
await expect( thirdStepLabel ).toHaveText(
'Confirm store requirements'
);
} );

test( 'should not have store requirements step if complete', async () => {
await setUpAccountsPage.goto();

// TODO: Mock email is verified & address is filled
setUpAccountsPage.mockMCSetup( 'complete', 'accounts' );

// 1. Assert there are 3 steps
const steps = await page.locator( '.woocommerce-stepper__step' );
await expect( steps ).toHaveCount( 3 );

// 2. Assert the label of the 3rd step is not 'Confirm store requirements'
const thirdStepLabel = await steps
.nth( 2 )
.locator( '.woocommerce-stepper__step-label' );
await expect( thirdStepLabel ).not.toHaveText(
'Confirm store requirements'
);

// 3. Assert the label of the 3rd step equals 'Create a campaign'
await expect( thirdStepLabel ).toHaveText( 'Create a campaign' );
} );
} );